/**
 * 
 */
package fr.utbm.gi.vi51.slizers.pw.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import fr.utbm.gi.vi51.slizers.framework.environment.EnvironmentEvent;
import fr.utbm.gi.vi51.slizers.framework.gui.GUI;
import fr.utbm.gi.vi51.slizers.pw.WorldManager;
import fr.utbm.gi.vi51.slizers.pw.environment.WorldMapEvent;
import fr.utbm.gi.vi51.slizers.pw.environment.WorldMapProvider;
import fr.utbm.gi.vi51.slizers.pw.environment.WorldStateEvent;
import fr.utbm.gi.vi51.slizers.pw.environment.WorldStateProvider;
import fr.utbm.gi.vi51.slizers.pw.gui.menu.MenuPanel;
import fr.utbm.gi.vi51.slizers.pw.gui.simulation.SimulationPanel;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;

import org.janusproject.kernel.locale.LocalizedString;

/**
 * Implementation of a world simulating application main frame. Contains two
 * independent displayed panels which will be the menu panel or the simulation
 * panel.
 * 
 * @author Tarik Belabbas
 * 
 */
public class ApplicationGUI extends JFrame implements GUI, LaunchSimulationListener
{
	/**
	 * Enum representing GUI panels.
	 * 
	 * @author Tarik Belabbas
	 * 
	 */
	public enum ApplicationGuiPanel
	{
		WORLD_PANEL,
		MENU_PANEL;
	}
	
	/**
	 * Version number associated to the serializable class.
	 */
	private static final long	serialVersionUID	= -4341987081134585157L;

	/**
	 * The world panel displayed in the GUI.
	 */
	private SimulationPanel			simulationPanel			= null;

	/**
	 * The menu panel displayed in the GUI
	 */
	private MenuPanel			menuPanel			= null;

	/**
	 * Constructor.
	 */
	public ApplicationGUI()
	{
		// Set up the window
		setTitle( LocalizedString.get( ApplicationGUI.class, "APPLICATION_NAME" ) ); //$NON-NLS-1$
		setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
		//setPreferredSize( new Dimension( 1024, 768 ) );
		
		Container content = getContentPane();
		content.setLayout( new BorderLayout() );
		
		// Set up the menu panel
		this.menuPanel	= new MenuPanel( this );
		getContentPane().add( this.menuPanel, BorderLayout.CENTER );

		// Add window close listener
		addWindowListener( new WindowAdapter()
		{
			@Override
			public void windowClosed( WindowEvent e )
			{
				WorldManager.stopSimulation();
			}
		} );
		
		// Create the top menu
		createTopMenu();

		// Automatically adjust the size of the window
		pack();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Window#paint(java.awt.Graphics)
	 */
	@Override
	public void paint( Graphics _graphics )
	{
		super.paint( _graphics );
		
		if ( this.menuPanel != null )
		{
			this.menuPanel.repaint();
		}
		else if ( this.simulationPanel != null )
		{
			this.simulationPanel.repaint();
		}
	}

	/**
	 * Create the top menu of the window.
	 */
	private void createTopMenu()
	{
		JMenuBar menu = new JMenuBar();
		
		// Help menu
		JMenu help = new JMenu( "?" ); //$NON-NLS-1$
		JMenuItem about = new JMenuItem( "About" ); //$NON-NLS-1$
		about.addActionListener( new ActionListener()
		{
			@Override
			public void actionPerformed( ActionEvent e )
			{
				JOptionPane.showMessageDialog(
								ApplicationGUI.this,
								"VI51 Slizers project - Tarik Belabbas & " + //$NON-NLS-1$
								"Adrien Hoffer & Vincent Perradin & Guillaume " + //$NON-NLS-1$
								"Vinson\n", "About", JOptionPane.NO_OPTION ); //$NON-NLS-1$ //$NON-NLS-2$
			}
		} );
		help.add( about );
		menu.add( help );
		
		this.setJMenuBar( menu );
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.utbm.gi.vi51.slizers.framework.environment.EnvironmentListener#
	 * environmentChanged
	 * (fr.utbm.gi.vi51.slizers.framework.environment.EnvironmentEvent)
	 */
	@Override
	public void environmentChanged( EnvironmentEvent _event )
	{
		synchronized ( getTreeLock() )
		{
			if ( _event instanceof WorldStateEvent )
			{
				WorldStateProvider world = ( ( WorldStateEvent)_event ).getStateProvider();
				if( world != null )
				{
					this.simulationPanel.setLastState( world.getState() );
				}
				
				repaint();
			}
			else if ( _event instanceof WorldMapEvent )
			{
				WorldMapProvider world = ( ( WorldMapEvent)_event ).getMapProvider();
				if( world != null )
				{
					this.simulationPanel.setLastMap( world.getMap() );
				}
				pack();
				repaint();
			}
		}
	}
	
	/**
	 * Switches to the specified panel.
	 * 
	 * @param _panel the panel to display
	 */
	private void switchToPanel( ApplicationGuiPanel _panel )
	{
		if ( ( _panel == ApplicationGuiPanel.MENU_PANEL ) && ( this.menuPanel == null ) )
		{
			getContentPane().remove( this.simulationPanel );
			this.simulationPanel	= null;
			
			this.menuPanel	= new MenuPanel( this );		
			getContentPane().add( this.menuPanel, BorderLayout.CENTER );
		}
		else if ( ( _panel == ApplicationGuiPanel.WORLD_PANEL ) && ( this.simulationPanel == null ) )
		{
			getContentPane().remove( this.menuPanel );
			this.menuPanel	= null;
			
			this.simulationPanel	= new SimulationPanel();
			getContentPane().add( this.simulationPanel, BorderLayout.CENTER );
		}
	}
	
	/**
	 * The size of world cells.
	 * 
	 * @param _cellSize the new cell size
	 */
	public void setCellSize( int _cellSize )
	{
		if ( this.simulationPanel != null )
		{
			this.simulationPanel.setCellSize( _cellSize );
			pack();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see fr.utbm.gi.vi51.slizers.pw.gui.LaunchSimulationListener#
	 * launchSimulationPressed()
	 */
	@Override
	public void launchSimulationPressed()
	{
		String mapPath = this.menuPanel.getSelectedMapPath();
		String creaturesPath = this.menuPanel.getSelectedCreaturesPath();
		int creaturesNb = this.menuPanel.getCreaturesNumber();
		
		if( mapPath != null )
		{
			switchToPanel( ApplicationGuiPanel.WORLD_PANEL );
			
			// Launch environment
			WorldManager.launchEnvironment( this );

			WorldManager.loadMap(  System.getProperty( "user.dir" ).concat( "/maps/" )  //$NON-NLS-1$ //$NON-NLS-2$
					+ mapPath );
			
			//Instantiate the creatures
			if( creaturesPath == "None" )
			{
				// Launch the number of creatures set by the user
				if ( !WorldManager.isSimulationRunning() )
				{
					for ( int i = 0; i < creaturesNb; ++i )
					{
						WorldManager.createCreature();
					}
				}
			}
			else
			{// Launch the number of creatures set by the user
				if ( !WorldManager.isSimulationRunning() )
				{
					WorldManager.loadCreatures(  System.getProperty( "user.dir" ).concat( "/creatures/" )  //$NON-NLS-1$ //$NON-NLS-2$
							+ creaturesPath );
				}
			}
			
			// Start simulation
			WorldManager.startSimulation();
		}
		else
		{
			JOptionPane.showMessageDialog( this, "Please select a map" );
		}
	}
}
